#import "msnmsgr.exe" tlbid(2) no_namespace, raw_interfaces_only

class MyMSN {
public:
	static MyMSN* GetMyMSN() {
		if (m_msn == NULL)
			m_msn = new MyMSN();

		return m_msn;
	}

	static void Release() {
		delete m_msn;
		m_msn = NULL;
	}

	BOOL ShowContactWindow(TCHAR* id, BOOL bCheckOnline) {
		HRESULT hr = S_OK;
		IDispatch* pIDispatch = NULL;

		VARIANT v;
		v.bstrVal = ::SysAllocString(id);
		v.vt = VT_BSTR;

		if (bCheckOnline) {
			MISTATUS status = GetStatus(v.bstrVal);
			if (status == MISTATUS_OFFLINE || status == (MISTATUS) -1) {
				goto RETURN;
			}
		}

		IMessengerWindow* w = NULL;
		
		hr = m_pMessenger->InstantMessage(v, (IDispatch**) &pIDispatch);
		if (hr != S_OK && hr != S_FALSE) {
			goto RETURN;
		}

		hr = pIDispatch->QueryInterface(__uuidof(IMessengerWindow), (void**) &w);
		if (FAILED(hr)) {
			goto RETURN;
		}

		SetFocus(w);

	RETURN:
		SysFreeString(v.bstrVal);

		if (pIDispatch)
			pIDispatch->Release();

		return FAILED(hr) ? FALSE : TRUE;
	}


	MISTATUS GetStatus(BSTR id) {
		BSTR emptyId = ::SysAllocString(L"");

		IMessengerContactPtr contact = NULL;
		IDispatch* pIDispatch;
		HRESULT hr = m_pMessenger->GetContact(id, emptyId, (IDispatch**) &pIDispatch);
		if (FAILED(hr)) {
			SysFreeString(emptyId);
			return (MISTATUS) -1;
		}

		::SysFreeString(emptyId);

		hr = pIDispatch->QueryInterface(__uuidof(IMessengerContact), (void**) &contact);
		if (FAILED(hr)) {
			return (MISTATUS) -1;
		}

		MISTATUS status;
		contact->get_Status(&status);

		return status;
	}

	inline void AutoSignin() {
		HRESULT hr = m_pMessenger->AutoSignin();
	}

	inline void Signout() {
		m_pMessenger->Signout();
	}

	void ShowWindow() {
		IDispatch* pIDispatch = NULL;
		IMessengerWindow* w;
		HRESULT hr = m_pMessenger->get_Window(&pIDispatch);
		if (hr != S_OK) {
			return;
		}

		hr = pIDispatch->QueryInterface(__uuidof(IMessengerWindow), (void**) &w);
		SetFocus(w);
		pIDispatch->Release();
	}

protected:
	MyMSN() {
		CoInitialize(0);
		m_pMessenger.CreateInstance(__uuidof(Messenger), NULL, CLSCTX_LOCAL_SERVER);
	}

	~MyMSN() {
		m_pMessenger.Release();
		CoUninitialize();
	}

	void SetFocus(IMessengerWindow* w) {
		w->Show();

		HWND lwnd;
		HRESULT hr = w->get_HWND((long*) &lwnd);
		if (hr != S_OK) {
			return;
		}

		HWND hwnd = lwnd;

		HWND hwndf = ::GetForegroundWindow();
		if (AttachThreadInput(GetWindowThreadProcessId(hwndf, NULL), GetWindowThreadProcessId(hwnd, NULL), TRUE) == TRUE) {
			::SetForegroundWindow(hwnd);
			::SetFocus(hwnd);

			AttachThreadInput(GetWindowThreadProcessId(hwndf, NULL), GetWindowThreadProcessId(hwnd, NULL), FALSE);
		}
	}

	static MyMSN* m_msn;

	IMessengerPtr m_pMessenger;
};

MyMSN* MyMSN::m_msn = NULL;
